import logging
from datetime import datetime

from src.models.adaboost import AdaBoost
from src.models.svm import SVM
from src.models.decisiontree import DecisionTree


def text2mod(config):
    """
    @brief 将模型名称和参数配置转换为模型对象列表
    @param config 配置字典，通常由yaml文件读取和预处理得到

    @details
    该函数根据配置字典中的模型类型、核函数、基分类器、迭代次数等参数，自动实例化对应的模型对象（如SVM、决策树、AdaBoost等）。
    同时会检查相关字段长度是否一致，并对整数参数进行类型转换和有效性校验。

    @return models 模型对象列表，每个元素为一个已配置好的模型实例
    @exception ValueError 字段长度不一致、参数无法转换为整数、未知模型类型或基分类器时抛出
    """

    # 检查模型相关字段长度是否一致
    model_keys = ['model', 'kernel', 'base_estimator', 'n_estimators', 'max_iter', 'max_depth']
    model_lens = [len(config[k]) for k in model_keys if isinstance(config[k], list)]
    if len(set(model_lens)) > 1:
        raise ValueError(f"配置文件错误：{model_keys} 字段长度不一致，分别为 {model_lens}")

    # 检查数据相关字段长度是否一致
    data_keys = ['dataset', 'train_size', 'test_ratio']
    data_lens = []
    for k in data_keys:
        v = config.get(k)
        if isinstance(v, list):
            data_lens.append(len(v))
        else:
            data_lens.append(1)
    if len(set(data_lens)) > 1:
        raise ValueError(f"配置文件错误：{data_keys} 字段长度不一致，分别为 {data_lens}")
    
    # 检查loss_curve与ada模型的关系
    if config.get('loss_curve', False):
        if not any(m == 'ada' for m in config['model']):
            raise ValueError("配置文件错误：loss_curve=True 时，model 列表中必须包含至少一个 'ada'。")
    
    # 创建模型对象列表
    n_models = len(config['model'])
    models = []

    # 遍历每个模型配置，实例化对应的模型对象
    for i in range(n_models):
        model_type = config['model'][i]
        kernel = config['kernel'][i] if 'kernel' in config and config['kernel'] else None
        base_estimator = config['base_estimator'][i] if 'base_estimator' in config and config['base_estimator'] else None
        n_estimators = config['n_estimators'][i] if 'n_estimators' in config and config['n_estimators'] else None
        max_iter = config['max_iter'][i] if 'max_iter' in config and config['max_iter'] else None
        max_depth = config['max_depth'][i] if 'max_depth' in config and config['max_depth'] else None
        
        # 转换max_iter为int
        if max_iter is not None:
            try:
                max_iter = int(max_iter)
            except Exception:
                raise ValueError(f"max_iter（第{i+1}个）无法转换为整数: {config['max_iter'][i]}")
        # 转换n_estimators为int
        if n_estimators is not None:
            try:
                n_estimators = int(n_estimators)
            except Exception:
                raise ValueError(f"n_estimators（第{i+1}个）无法转换为整数: {config['n_estimators'][i]}")
        # 转换n_estimators为int
        if n_estimators is not None:
            try:
                n_estimators = int(n_estimators)
            except Exception:
                raise ValueError(f"n_estimators（第{i+1}个）无法转换为整数: {config['n_estimators'][i]}")
        # 转换max_depth为int
        if max_depth is not None:
            try:
                max_depth = int(max_depth)
            except Exception:
                raise ValueError(f"max_depth（第{i+1}个）无法转换为整数: {config['max_depth'][i]}")

        if model_type == 'svm':
            model = SVM(kernel=kernel or 'linear', max_iter=max_iter)
        elif model_type == 'decision_tree':
            model = DecisionTree(max_depth=max_depth or 1)
        elif model_type == 'ada':
            # AdaBoost基分类器选择
            if base_estimator == 'linear_svm':
                base = SVM(kernel='linear', max_iter=max_iter)
            elif base_estimator == 'decision_tree':
                base = DecisionTree(max_depth=max_depth or 1)
            else:
                raise ValueError(f"未知的AdaBoost基分类器: {base_estimator}")
            model = AdaBoost(base, n_estimators=n_estimators or 20)
        else:
            raise ValueError(f'未知的模型类型: {model_type}')
        
        now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        logging.info(f"[{now}] 已实例化模型: {model_type}, 参数: kernel={kernel}, base_estimator={base_estimator}, n_estimators={n_estimators}, max_iter={max_iter}, max_depth={max_depth}")
        
        models.append(model)

    return models